前面3篇都是說明讀取歷史資料,那如果想要即時觀測的資料呢?
那就可以利用氣象局opendata網站
建議大家可以去申請一組帳號,因為接下來介紹的資料大概都是從開方資料下載。
相關透過API下載的方式在網路上都有許多參考文章,我就不贅述了。
這一篇主要說明xml的讀取方式,主要使用基本的xml.etree.ElementTree來處理。
其實有xmltodict的套件可以使用,可能會簡單多XD。
登入氣象局opendata後,下載自動氣象站-氣象觀測資料(xml格式。)
下載完成後,檔案名稱應該是O-A0001-001.xml。
用記事本或者網頁方式打開,如下圖所示(擷取部分)。
我們可以看到是類似html的格式,所以就屬於標籤格式類的資料儲存方式。
稍微解釋一下,每一個向下的灰色三角形代表的是一個區塊的標籤標記
第一層是cwbopendata,再這一層之後,還有第二層location,其它以此類推。
那每一個有屬於該層的訊息及後一層的標籤標記。
以location層為例,location層的直接資訊有lat、lon等,而下一層的標籤標記有time、weatherElement、parameter。
所以,今天要將資料抓出來顯示,就類似一層一層剝洋蔥的方式將資料萃取。
接下來以程式碼實作
先import xml.etree.ElementTree,然後把最基本的根抓出來,
import xml.etree.ElementTree as ET
import pandas as pd
trees = ET.parse('O-A0001-001.xml')
roots = trees.getroot()
對根物件進行基本的處理,看最基本的節點標記
for child in roots:
print(child.tag)
結果如圖所示(擷取部分),對照上面xml檔案內容,可以看到最基本的節點標記是第一層cwbopendata的直接資訊及下一層的location標記。由於已經先看到我們需要的資料都在location層,因此直接對location進行處理。
由上述的結果可以觀察到一件事,選擇某一層標記時,會僅回傳該層的直接資訊與下一層的標記,所以選擇location時,可以知道會回傳該層的直接資訊lat, lon, lat_wgs84, lon_wgs84, loctionName, stationId及下一層的標記time, weatherElement, parameter。來實證一下,我們使用根結點直接抓取location標記的方法(iter),然後把該層的直接資訊及下一層的標記資訊print出來顯示,就如下圖所示。
那要如何取得資料呢?
如果是該層資料的話,只要用location層及該層資訊配合text方法即可。
如下程式,在每個location層中,取該層的lat標記,然後使用text方法
那如果是location的下一層呢?
假設取weatherElement層,這一層的直接資訊有elementName及下一層有elementValue標記
如果是該層的直接資訊,就取第0個位置後,然後使用text方法,這邊要加個0是因為相對location來說,weatherElement已經是下一層的標記位置,而weatherElement有一個直接資訊elementName,所以對location來說,elementName的位置是weatherElement的第0個位置。
所以簡單來說,該層的直接資訊不用加第0個位置資訊。
###第一段
for locationtags in roots.iter("{urn:cwb:gov:tw:cwbcommon:0.1}location"):
for xx in locationtags.iter("{urn:cwb:gov:tw:cwbcommon:0.1}lat"):
print(xx.text)
###第二段
for locationtags in roots.iter("{urn:cwb:gov:tw:cwbcommon:0.1}location"):
for xx in locationtags.iter("{urn:cwb:gov:tw:cwbcommon:0.1}weatherElement"):
print(xx[0].text)
for xxin in xx.iter("{urn:cwb:gov:tw:cwbcommon:0.1}elementValue"):
print(xxin[0].text)
由上述的取直說明,開始寫成函式,如果是以location為基準的狀況下,就是以一個測站為基準,
loc_element = ['{urn:cwb:gov:tw:cwbcommon:0.1}time',
'{urn:cwb:gov:tw:cwbcommon:0.1}stationId',
'{urn:cwb:gov:tw:cwbcommon:0.1}locationName',
'{urn:cwb:gov:tw:cwbcommon:0.1}lon',
'{urn:cwb:gov:tw:cwbcommon:0.1}lat',
'{urn:cwb:gov:tw:cwbcommon:0.1}lon_wgs84',
'{urn:cwb:gov:tw:cwbcommon:0.1}lat_wgs84',
'{urn:cwb:gov:tw:cwbcommon:0.1}weatherElement',
'{urn:cwb:gov:tw:cwbcommon:0.1}parameter',
] #將location 該層直接資訊及下一層標記寫成list
def onestn(lociter, elements):
"""
lociter代表針對根的location的iter,即roots.iter("{urn:cwb:gov:tw:cwbcommon:0.1}location")
以此份資料來說,一個location代表一個測站。
elements代表location的該層資訊及下一層標記。
"""
valu, header = [],[] #儲存數值及檔頭用
cnt = 1
itercol = [ loctag.iter(eachtag) for eachtag in elements] #先對每個element進行iter
for eachiter, eachelement in zip(itercol,elements):
for elements in eachiter:
if "weatherElement" not in eachelement and "parameter" not in eachelement and "time" not in eachelement:
header.append(eachelement.split("}")[-1])
valu.append(elements.text)
else:
for qqinin in elements:
if "weatherElement" in eachelement:
for xxin in qqinin.iter("{urn:cwb:gov:tw:cwbcommon:0.1}elementName"):
if cnt == 1:
header.append(xxin.text)
for xxin in qqinin.iter("{urn:cwb:gov:tw:cwbcommon:0.1}elementValue"):
valu.append(xxin[0].text)
elif "parameter" in eachelement:
for xxin in qqinin.iter("{urn:cwb:gov:tw:cwbcommon:0.1}parameterName"):
if cnt ==1:
header.append(xxin.text)
for xxin in qqinin.iter("{urn:cwb:gov:tw:cwbcommon:0.1}parameterValue"):
valu.append(xxin.text)
else:
header.append(eachelement.split("}")[-1])
valu.append(qqinin.text)
cnt = 2
return header, valu
將上述的函式待配所有資料及pandas 應用,這樣就可以完成一個觀測資料表囉。
packvalue = []
for qq in roots.iter("{urn:cwb:gov:tw:cwbcommon:0.1}location"):
ch, eachvalue = onestn(qq,loc_element)
packvalue.append(eachvalue)
df = pd.DataFrame(packvalue,columns=ch)
print(df)
簡單畫個圖
import matplotlib.pyplot as plt
import os
os.environ["PROJ_LIB"] = "PATH to your shared proj directory"
# For example D:\ithome\Miniconda3\envs\pltenv\Library\share\proj"
from mpl_toolkits.basemap import Basemap
import matplotlib.colors as mcolors
cwb_Tcolor=['#117388','#207E92','#2E899C','#3D93A6','#4C9EB0','#5BA9BA','#69B4C4','#78BFCE','#87CAD8',\
'#96D4E2','#A4DFEC','#B3EAF6','#0C924B','#1D9A51','#2FA257','#40A95E','#51B164','#62B96A',\
'#74C170','#85C876','#96D07C','#A7D883','#B9E089','#CAE78F','#DBEF95','#F4F4C3','#F7E78A',\
'#F4D576','#F1C362','#EEB14E','#EA9E3A','#E78C26','#E07B03','#ED5138','#ED1759','#AD053A',\
'#780101','#9C68AD','#845194','#8520A0']
clevs = list(range(-1,39))
clevs.insert(0,-10)
cmaps = mcolors.ListedColormap(cwb_Tcolor,'temp')
norms = mcolors.BoundaryNorm(clevs, cmaps.N)
hh = list(df)
print(hh)
lat = df["lat"].astype(float).values
lon = df["lon"].astype(float).values
tempature = df["TEMP"].astype(float).values
obstime = df["time"]
plt.figure(figsize=(16,12))
m = Basemap(projection='merc',urcrnrlat=26, llcrnrlat=21.5, llcrnrlon=117.5, urcrnrlon=122.5 )
m.readshapefile("D:\ithome\/tw_shp\COUNTY_MOI_1090820","tw_shp")
sct = m.scatter(lon, lat, c=tempature, cmap=cmaps,norm=norms, latlon=True)
plt.colorbar(sct)
plt.title(obstime[0],fontsize=18)
plt.show()